import type { Result } from "../util/handler";
import { handleResponse } from "../util/handler";

export type ProductAttribute = {
  attributeId: number;
  color: string;
  unitPrice: number;
  stock: number;
  productId: number;
  imgPath: string;
}

export interface ProductInfo {
  productId: number;
  productName: string;
  categoryId: number;
  storeId: number;
  attribute: ProductAttribute[];
}

async function createProduct({ productName, categoryId, storeId, token }: { productName: string; categoryId: number; storeId: number; token: string }): Promise<Result<null>> {
  return await fetch('/api/product/createProduct', {
    method: 'post',
    credentials: 'same-origin',
    body: JSON.stringify({
      productName,
      categoryId,
      storeId
    }),
    headers: {
      'content-type': 'application/json',
      'token': token
    }
  }).then((resp) => handleResponse<null>(resp));
}

async function findAllProduct({ storeId, token }: { storeId: number; token: string }): Promise<Result<ProductInfo[]>> {
  return await fetch('/api/product/findAllProduct', {
    method: 'post',
    credentials: 'same-origin',
    body: new URLSearchParams({ storeId: ''+storeId }),
    headers: {
      'content-type': 'application/x-www-form-urlencoded',
      'token': token
    }
  }).then((resp) => handleResponse<ProductInfo[]>(resp));
}

async function updateProduct({
  productId,
  productName,
  categoryId,
  storeId,
  token
}: { [P in Exclude<keyof ProductInfo, 'attribute'>]: ProductInfo[P] } & { token: string }): Promise<Result<null>> {
  return await fetch('/api/product/updateProduct', {
    method: 'post',
    credentials: 'same-origin',
    body: JSON.stringify({
      productId,
      productName,
      categoryId,
      storeId
    }),
    headers: {
      'content-type': 'application/json',
      'token': token
    }
  }).then((resp) => handleResponse<null>(resp));
}

async function deleteProduct({ productId, token }: { productId: number; token: string }): Promise<Result<null>> {
  return await fetch('/api/product/deleteProduct', {
    method: 'post',
    credentials: 'same-origin',
    body: new URLSearchParams({
      productId: ''+productId
    }),
    headers: {
      'content-type': 'application/x-www-form-urlencoded',
      'token': token
    }
  }).then((resp) => handleResponse<null>(resp));
}

const getType = Function.prototype.call.bind(Object.prototype.toString);
const createFormData = (o: Record<string, unknown>) => {
  const formData = new FormData();
  Object.entries(o)
    .forEach(([k, v]: [string, unknown]) => {
      if (typeof v == 'number') {
        v = '' + v;
      }
      if (typeof v != 'string' && !(v instanceof File)) {
        throw new TypeError(`couldn't handle ${v}, ${getType(v)}`);
      }
      if (typeof v == 'string') formData.append(k, v);
      else formData.append(k, v, v.name);
    });
  return formData;
};

async function createProductAttributes(params: { [P in Exclude<keyof ProductAttribute, 'attributeId'>]: ProductAttribute[P] } & { img?: File; token: string }): Promise<Result<null>> {
  const formData = createFormData(params);

  return await fetch('/api/product/createProductAttribute', {
    method: 'post',
    credentials: 'same-origin',
    body: formData,
    headers: {
      'token': params.token
    }
  }).then((resp) => handleResponse<null>(resp));
}

async function updateProductAttributes(params: ProductAttribute & { img?: File; token: string }): Promise<Result<null>> {
  const formData = createFormData(params);

  return await fetch('/api/product/updateProductAttribute', {
    method: 'post',
    credentials: 'same-origin',
    body: formData,
    headers: {
      'token': params.token
    }
  }).then((resp) => handleResponse<null>(resp));
}

async function deleteProductAttributes(params: { attributeId: number; token: string }): Promise<Result<null>> {
  return await fetch('/api/product/deleteProductAttribute', {
    method: 'post',
    credentials: 'same-origin',
    body: new URLSearchParams({ attributeId: ''+params.attributeId }),
    headers: {
      'content-type': 'application/x-www-form-urlencoded',
      'token': params.token
    }
  }).then((resp) => handleResponse<null>(resp));
}

export {
  findAllProduct,
  createProduct,
  updateProduct,
  deleteProduct,

  createProductAttributes,
  updateProductAttributes,
  deleteProductAttributes
}
